package com.sugon.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.sugon.consts.ErmsCodePrefix;
import com.sugon.consts.FactoryTypeEnum;
import com.sugon.dao.DeviceInfoDao;
import com.sugon.dao.SysDeptDao;
import com.sugon.entity.*;
import com.sugon.modules.sys.consts.SysDeptConst;
import com.sugon.service.*;
import com.sugon.utils.*;
import com.sugon.utils.excel.ExcelImport;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.sugon.utils.ShiroUtils.getUserId;

/**
 * 设备信息Service实现类
 *
 * @author sugon
 * @date 2019-07-15 08:37:25
 */
@Slf4j
@Service("deviceInfoService")
public class DeviceInfoServiceImpl implements DeviceInfoService {

    @Resource
    private DeviceInfoDao deviceInfoDao;
    @Resource
    private DevFileService devFileService;
    @Resource
    private FactoryTypeService factoryTypeService;
    @Resource
    private SysDeptDao sysDeptDao;
    @Resource
    private SysDeptService deptService;
    @Resource
    private SysMsgService sysmsgService;
    @Resource
    private DeviceLifeSpanRecordService deviceLifeSpanRecordService;
    @Resource
    private SysConfigService configService;

    @Override
    public String generateNameplate(DeviceInfoEntity device) {

        String temSavePath = configService.getTemSavePath();

        QrConfig qrConfig = new QrConfig(300, 300);
        qrConfig.setMargin(0);
        ImageUtil tt = new ImageUtil();
        BufferedImage d = tt.loadImageLocal(temSavePath + "/blankTemplate.jpg");

        /*
            1、写字
            2、画图：二维码、条形码
            3、上传到服务器
         */
        /********************开始部分*******************/

        //设备编码
        String devCode = device.getDevCode();
        if (devCode.length() <= 17) {
            tt.modifyImage(temSavePath, d, devCode, -300, -170);
        } else {
            tt.modifyImage(temSavePath, d, devCode.substring(0, 17), -300, -170);
            tt.modifyImage(temSavePath, d, devCode.substring(17), -300, -115);
        }
        //erp编号
        String devErpCode = device.getErpCode();
        if (StrUtil.isNotEmpty(devErpCode)) {
            if (devErpCode.length() <= 17) {
                tt.modifyImage(temSavePath, d, devErpCode, -300, -51);
            } else {
                tt.modifyImage(temSavePath, d, devErpCode.substring(0, 17), -300, -51);
                tt.modifyImage(temSavePath, d, devErpCode.substring(17), -300, 5);
            }
        }

        //固定资产
        String devFirmNo = device.getFirmNo();
        if (StrUtil.isNotEmpty(devFirmNo)) {
            if (devFirmNo.length() <= 17) {
                tt.modifyImage(temSavePath, d, devFirmNo, -300, 70);
            } else {
                tt.modifyImage(temSavePath, d, devFirmNo.substring(0, 17), -300, 70);
                tt.modifyImage(temSavePath, d, devFirmNo.substring(17), -300, 120);
            }

        }

        //产线代码
        String devProductCode = device.getDevProductCode();
        if (devProductCode.length() <= 14) {
            tt.modifyImage(temSavePath, d, devProductCode, -300, 187);
        } else {
            tt.modifyImage(temSavePath, d, devProductCode.substring(0, 14), -300, 187);
            tt.modifyImage(temSavePath, d, devProductCode.substring(14), -300, 237);
        }
        // 设备名称
        String devName = device.getDevName();
        devName = devName.replaceAll("、", "");
        devName = devName.replaceAll("\n", "");
        if (devName.length() <= 12) {
            tt.modifyImage(temSavePath, d, devName, -300, 305);
        } else {
            tt.modifyImage(temSavePath, d, devName.substring(0, 12), -300, 305);
            tt.modifyImage(temSavePath, d, devName.substring(12), -300, 360);
        }

        //条形码
        tt.modifyImagetogeter(BarCodeUtil.getBarCode(device.getDevCode()), d, 805, 630);
        //二维码
        tt.modifyImagetogeter(QrCodeUtil.generate(device.getDevCode(), qrConfig), d, 805, 250);

        /********************结束部分*******************/
        // 3、上传到服务器
        return writeImage2Minio(d);
    }

    /**
     * 将生成的图片上传到MINIO
     *
     * @param img
     */
    public String writeImage2Minio(BufferedImage img) {
        String devNameplateUrl = null;
        if (img != null) {
            try {
                // 先暂存文件，然后上传MINIO
                String temSavePath = configService.getTemSavePath();
                String fileName = RandomUtil.randomString(32) + ".jpg";
                File tempFile = FileUtil.file(temSavePath, fileName);
                ImageIO.write(img, "jpg", tempFile);
                // 然后上传
                BufferedInputStream inputStream = FileUtil.getInputStream(tempFile);
                devNameplateUrl = MinioUtil.upload(inputStream, "device/nameplate", fileName);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        return devNameplateUrl;
    }

    /**
     * queryObject
     *
     * @param id 主键
     * @return
     */
    @Override
    public DeviceInfoEntity queryObject(String id) {
        return deviceInfoDao.queryObject(id);
    }

    /**
     * queryList
     *
     * @param map 参数
     * @return
     */
    @Override
    public List<DeviceInfoEntity> queryList(Map<String, Object> map) {
        // 设置部门权限查询参数
        setDeptViewParam(map);
        return deviceInfoDao.queryList(map);
    }

    /**
     * 设置部门查看权限参数
     *
     * @param map
     */
    private void setDeptViewParam(Map<String, Object> map) {
    /*
    如果含有模具关联，那么说明为查看所有关联模具的设备，不应该根据组织区分
    1、如果是制造处，那么可以查看所有的
        然后根据用户选择的设备组织树查看即可
    2、车间用户只可以查看自己车间下的
        然后对比用户选择的组织设备树
            如果一致，那么按照用户选择的查询
            如果不一致，那么认为不是一个车间的，不允许查看
     */
        String isModuleRelated = MapUtil.getStr(map, "isModuleRelated");
        if (StrUtil.isEmpty(isModuleRelated)) {
            String deptCode = MapUtil.getStr(map, "deptId");
            if (StrUtil.isEmpty(deptCode)) {
                deptCode = ShiroUtils.getDeptId();
            }
            if (StrUtil.isNotEmpty(deptCode)) {
                if (deptCode.startsWith(SysDeptConst.ZZC_CODE)) {
                    // 获取设备组织ID
                    deptCode = MapUtil.getStr(map, "deptCode");
                    if (StrUtil.isNotEmpty(deptCode)) {
                        map.put("deptCode", deptCode);
                    }
                } else {
                    if (deptCode.length() > 3) {
                        deptCode = deptCode.substring(0, 4);
                        // 获取登陆用户想要查看的设备组织ID
                        String deptId = MapUtil.getStr(map, "deptCode");
                        if (StrUtil.isNotEmpty(deptId) && deptId.length() > 3) {
                            if (deptCode.equals(deptId.substring(0, 4))) {
                                deptCode = deptId;
                            } else {
                                // 不一致，说明想跨部门查看，不允许,简单处理下
                                deptCode = "999999999";
                            }
                        }
                        map.put("deptCode", deptCode);
                    }
                }
            }
        }
    }

    /**
     * queryTotal
     *
     * @param map 参数
     * @return
     */
    @Override
    public int queryTotal(Map<String, Object> map) {
        // 设置部门权限查询参数
        setDeptViewParam(map);
        return deviceInfoDao.queryTotal(map);
    }

    /**
     * save
     *
     * @param deviceInfo 实体
     * @return
     */
    @Override
    public int save(DeviceInfoEntity deviceInfo) {
        deviceInfo.setId(RandomUtil.randomString(32));
        deviceInfo.setCreateDate(DateUtil.date());
        deviceInfo.setCheckDate(DateUtil.date());
        deviceInfo.setCreateUser(getUserId());
        // 设置设备编码
        String code = generateDevice(deviceInfo.getDevTypeB(), null);
        deviceInfo.setDevCode(code);
        deviceInfo.setReserve4("0");
        deviceInfo.setDelFlag(1);
        // 如果未设置是否关联模具，那么暂时设置为未关联模具
        if (deviceInfo.getIsModuleRelated() == null) {
            deviceInfo.setIsModuleRelated(0);
        }
        // 设置车间ID和名称
        String deptCode = deviceInfo.getDeptCode();
        if (StrUtil.isNotEmpty(deptCode)) {
            SysDeptEntity workshop = sysDeptDao.queryObject(StrUtil.sub(deptCode, 0, 4));
            if (workshop != null) {
                deviceInfo.setDevFarm(workshop.getDeptId());
                deviceInfo.setDevFarmName(workshop.getName());
            }
        }
        int rows = deviceInfoDao.save(deviceInfo);
        if (rows > 0) {
            // 保存下设备图片
            String devImgUrl = deviceInfo.getUrl();
            if (StrUtil.isNotEmpty(devImgUrl)) {
                //设备图片
                DevFileEntity devFile = new DevFileEntity();
                devFile.setFileType(1);
                devFile.setUrl(devImgUrl);
                devFile.setDevId(deviceInfo.getId());
                devFileService.save(devFile);

                String devId = deviceInfo.getId();
                SysMsgEntity msgEntity = new SysMsgEntity();
                msgEntity.setDataId(devId);
                msgEntity.setDataUrl("../sys/deviceinfo.html?devId=" + devId);
                sysmsgService.addApproveItem(ProcessInfoEnum.DEV_SBQD, msgEntity, 0);
            }
        }
        return rows;
    }

    /**
     * 递归生成设备编码，确保唯一
     * generateDevice
     *
     * @param typeB
     * @param deviceCode
     * @return
     */
    private synchronized String generateDevice(String typeB, String deviceCode) {
        if (StrUtil.isEmpty(deviceCode)) {
            deviceCode = deviceInfoDao.queryMaxCode(typeB);
        }
        // 生成新的唯一编码
        deviceCode = com.sugon.modules.utils.StrUtil.increase(deviceCode, ErmsCodePrefix.DEVICE_CODE_PREFIX + typeB + "-", 5, 1);
        // 确保最新生成备件编码不重复
        DeviceInfoEntity device = getInfoByDevCode(deviceCode);
        if (device == null) {
            return deviceCode;
        }
        return generateDevice(typeB, deviceCode);
    }

    /**
     * update
     *
     * @param deviceInfo 实体
     * @return
     */
    @Override
    public int update(DeviceInfoEntity deviceInfo) {
        // 需要重新设置下车间和车间名称
        String deptCode = deviceInfo.getDeptCode();
        if (StrUtil.isNotEmpty(deptCode) && deptCode.length() >= 4) {
            SysDeptEntity workshop = sysDeptDao.queryObject(StrUtil.sub(deptCode, 0, 4));
            if (workshop != null) {
                deviceInfo.setDevFarm(workshop.getDeptId());
                deviceInfo.setDevFarmName(workshop.getName());
            }
        }

        //查询设备图图片 add or update
//        Map<String, Object> map = new HashMap<>();
//        String devId = deviceInfo.getId();
//        map.put("devId", devId);
//        map.put("fileType", "1");
//        List<DevFileEntity> devFile = devFileService.queryList(map);
//        if (devFile.size() > 0) {
//            for (DevFileEntity devFileEntity : devFile) {
//                devFileEntity.setUrl(deviceInfo.getUrl());
//                devFileService.update(devFileEntity);
//            }
//        } else {
//            DevFileEntity devFile1 = new DevFileEntity();
//            devFile1.setFileType(1);
//            devFile1.setUrl(deviceInfo.getUrl());
//            devFile1.setDevId(deviceInfo.getId());
//            devFileService.save(devFile1);
//        }
        deviceInfo.setUpdateUser(getUserId());
        deviceInfo.setUpdateDate(new Date());

        int rows = deviceInfoDao.update(deviceInfo);
        if (rows > 0) {
            SysMsgEntity msgEntity = new SysMsgEntity();
            msgEntity.setDataId(deviceInfo.getId());
            msgEntity.setDataUrl("../sys/deviceinfo.html?devId=" + deviceInfo.getId());
            sysmsgService.addApproveItem(ProcessInfoEnum.DEV_SBQD, msgEntity, 0);
        }
        return rows;
    }

    /**
     * delete
     *
     * @param id
     * @return
     */
    @Override
    public int delete(String id) {
        return deviceInfoDao.delete(id);
    }

    /**
     * deleteBatch
     *
     * @param ids
     * @return
     */
    @Override
    public int deleteBatch(String[] ids) {
        return deviceInfoDao.deleteBatch(ids);
    }

    /**
     * deviceInfoAll
     *
     * @return
     */
    @Override
    public List<Map<String, Object>> deviceInfoAll() {
        return deviceInfoDao.deviceInfoAll();
    }

    /**
     * getInfoByDevCode
     *
     * @param devCode
     * @return
     */
    @Override
    public DeviceInfoEntity getInfoByDevCode(String devCode) {
        return deviceInfoDao.getInfoByDevCode(devCode);
    }

    @Override
    public DeviceInfoEntity queryByDevLastCode(String... deviceUniqueParam) {
        // 构建唯一码
        List<String> devUniqueParamList = CollectionUtil.newArrayList(deviceUniqueParam);
        String devLastCode = CollectionUtil.join(CollectionUtil.removeNull(devUniqueParamList), ",");
        // 构建查询参数
        DeviceInfoEntity param = new DeviceInfoEntity();
        param.setDevLastCode(devLastCode);
        List<DeviceInfoEntity> deviceList = queryList(BeanUtil.beanToMap(param));
        return CollectionUtil.isNotEmpty(deviceList) ? deviceList.get(0) : null;
    }

    /**
     * updateStatus
     *
     * @param devId  设备ID
     * @param status 设备状态
     * @return
     */
    @Override
    public int updateStatus(String devId, String status) {
        Map<String, Object> param = new HashMap<>();
        param.put("id", devId);
        param.put("devStatus", status);
        int rows = deviceInfoDao.update(param);
        if (rows > 0) {
            SysMsgEntity msgEntity = new SysMsgEntity();
            msgEntity.setDataId(devId);
            msgEntity.setDataUrl("../sys/devleaverecord.html?devId=" + devId);
            sysmsgService.addApproveItem(ProcessInfoEnum.DEV_SBXZ, msgEntity, 0);
        }
        return rows;
    }

    @Override
    public List<DeviceInfoEntity> getDevInfo(Object[] ids) {
        return deviceInfoDao.getDevInfo(ids);
    }

    @Override
    public int updateView(String id) {
        int rows = deviceInfoDao.updateView(id);
        if (rows > 0) {
            SysMsgEntity sysMsgEntity = new SysMsgEntity();
            DeviceInfoEntity deviceInfo = new DeviceInfoEntity();
            String devId = deviceInfo.getId();
            sysMsgEntity.setDataId(devId);
            sysMsgEntity.setDataType(ProcessInfoEnum.DEV_SBXZ);
            sysMsgEntity.setDataFlag(SysMsgType.DATA_DEL_END);
            sysmsgService.allMsgData(sysMsgEntity);
        }
        return rows;
    }

    @Override
    public int check(String id) {
        int rows = deviceInfoDao.check(id);
        if (rows > 0) {
            SysMsgEntity sysMsgEntity = new SysMsgEntity();
            DeviceInfoEntity deviceInfo = new DeviceInfoEntity();
            String devId = deviceInfo.getId();
            sysMsgEntity.setDataId(devId);
            sysMsgEntity.setDataType(ProcessInfoEnum.DEV_SBQD);
            sysMsgEntity.setDataFlag(SysMsgType.DATA_DEL_END);
            sysmsgService.allMsgData(sysMsgEntity);
        }
        return rows;
    }

    /**
     * 保存或更新导入的设备清单信息
     *
     * @param file
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int imports(MultipartFile file) {
        int num = 0;
        if (file.isEmpty()) {
            throw new RRException("上传文件不能为空");
        }
        List<String[]> list = ExcelImport.getExcelData(file);
        if (CollectionUtil.isNotEmpty(list)) {
            // 获取设备供应商列表
            List<FactoryTypeEntity> deviceFactoryList = factoryTypeService.queryListByType(FactoryTypeEnum.DEVICE);
            Map<String, String> factoryMap = deviceFactoryList.stream().collect(Collectors.toMap(FactoryTypeEntity::getFaName, FactoryTypeEntity::getId));

            for (int i = 1; i < list.size(); i++) {
                String[] array = list.get(i);
                array = ArrayUtil.resize(array, 28);
                DeviceInfoEntity device = null;
                // 如果导入模板中含有备件编码，则查询并更新
                String devCode = array[1];
                boolean isSave = false;
                if (StrUtil.isNotEmpty(devCode)) {
                    device = deviceInfoDao.getInfoByDevCode(devCode);
                }
                if (device == null) {
                    isSave = true;
                    device = new DeviceInfoEntity();
                }
                device.setDevName(array[0]);
                device.setDevCode(array[1]);
                device.setDevDescr(array[2]);
                device.setDevLastCode(array[3]);
                device.setDevTypeB(array[4]);
                device.setDevTypeM(array[5]);
                device.setDevTypeS(array[6]);
                device.setDevProductName(array[7]);
                device.setDevProductCode(array[8]);
                device.setDevProceName(array[9]);
                device.setDevProceNo(array[10]);
                setDeptCode(device, array[8]);
                device.setUrCode(array[11]);
                // 根据设备供应商名称查询已存在的设备供应商
                String supplierId = factoryMap.get(array[12]);
                Assert.notBlank(supplierId, "设备供应商[{}]不存在，请确认！", array[12]);
                device.setSupplierId(supplierId);
                device.setDevStatus(array[13]);
                device.setReserve1(array[14]);
                device.setReserve2(array[15]);
                device.setDevProject(array[16]);
                device.setDevKind(array[17]);
                device.setFirmNo(array[18]);
                if (StrUtil.isNotEmpty(array[19])) {
                    device.setCheckDate(DateUtil.parseDate(array[19]));
                }
                if (StrUtil.isNotEmpty(array[20])) {
                    device.setInstallDate(DateUtil.parseDate(array[20]));
                }
                device.setRegNo(array[21]);
                device.setDevContractCode(array[22]);
                device.setInitCode(array[23]);
                // 下次保养寿命
                if (StrUtil.isNotEmpty(array[24])) {
                    device.setMaintenanceLifeSpan(Long.parseLong(array[24]));
                }
                // 当前寿命
                Long oldCurrentLifeSpan = 0L;
                if (StrUtil.isNotEmpty(array[25])) {
                    if (device.getCurrentLifeSpan() != null) {
                        oldCurrentLifeSpan = device.getCurrentLifeSpan();
                    }
                    device.setCurrentLifeSpan(Long.parseLong(array[25]));
                }
                // ERP编码
                device.setErpCode(array[26]);
                // 控制系统代码
                if (StrUtil.isNotEmpty(array[27])) {
                    device.setCsCode(array[27].toLowerCase());
                }
                if (isSave) {
                    num += save(device);
                } else {
                    // 寿命记录变化时需要记录变更内容
                    if (!(device.getCurrentLifeSpan() == null || NumberUtil.equals(oldCurrentLifeSpan, device.getCurrentLifeSpan()))) {
                        DeviceLifeSpanRecordEntity lifeSpanRecord = new DeviceLifeSpanRecordEntity();
                        lifeSpanRecord.setDevId(device.getId());
                        lifeSpanRecord.setCurrentLifeSpan(device.getCurrentLifeSpan());
                        lifeSpanRecord.setMaintenanceLifeSpan(device.getMaintenanceLifeSpan());
                        deviceLifeSpanRecordService.save(lifeSpanRecord);
                    }
                    num += update(device);
                }
            }
        }
        return num;
    }

    @Override
    public Map<String, Object> prepareExportData(Map<String, Object> params) {
        Map<String, Object> resultMap = MapUtil.newHashMap();
        //List<DeviceInfoEntity> deviceList = queryList(params);
        resultMap.put("list", queryList(params));
        return resultMap;
    }

    /**
     * 由于在不同产线下存在工序一样的情况
     * 所以必须找出指定产线下的工序
     * 1、根据产线的dcode找出产线信息
     * 2、根据产线ID和工序编码找出该工序的ID并设置
     *
     * @param deviceInfoEntity 设备信息
     * @param lineDCode        产线编码
     */
    private void setDeptCode(DeviceInfoEntity deviceInfoEntity, String lineDCode) {
        List<SysDeptEntity> lineList = sysDeptDao.queryByDCode(lineDCode);
        if (CollectionUtil.isEmpty(lineList)) {
            return;
        }
        Map<String, Object> queryParam = new HashMap<>();
        queryParam.put("dcode", deviceInfoEntity.getDevProceNo());
        queryParam.put("parentId", lineList.get(0).getDeptId());
        List<SysDeptEntity> depts = sysDeptDao.queryList(queryParam);
        if (CollectionUtil.isNotEmpty(depts)) {
            deviceInfoEntity.setDeptCode(depts.get(0).getDeptId());
            // 设置设备所在车间ID和车间名称
            setWorkshop(deviceInfoEntity, depts.get(0).getDeptId());
        }
    }

    /**
     * 设置生产设备的车间名称和编码
     *
     * @param deviceInfoEntity
     * @param proCode
     * @return
     */
    private String setWorkshop(DeviceInfoEntity deviceInfoEntity, String proCode) {
        SysDeptEntity dept = deptService.getByDCode(proCode);
        if (dept != null) {
            // 获取产线编码,从编码中找出车间编码
            String code = dept.getDeptId();
            if (StrUtil.isNotEmpty(code) && code.length() > 4) {
                dept = deptService.queryObject(code.substring(0, 4));
                if (dept != null) {
                    deviceInfoEntity.setDevFarm(dept.getDeptId());
                    deviceInfoEntity.setDevFarmName(dept.getName());
                }
            }
            return code;
        }
        return null;
    }

}
